package com.mate.cloud.redis.service.impl;


import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mate.cloud.core.util.CollectionUtils;
import com.mate.cloud.redis.constants.RedisKeyConstants;
import com.mate.cloud.redis.dal.mapper.CityMapper;
import com.mate.cloud.redis.dal.model.City;
import com.mate.cloud.redis.service.ICityService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author astupidcoder
 * @since 2021-06-26
 */
@Slf4j
@Service
public class CityServiceImpl extends ServiceImpl<CityMapper, City> implements ICityService {


    @Autowired
    StringRedisTemplate redisTemplate;


    @Override
    public City queryCityById(Integer id) {
        return this.queryCityById(String.format(RedisKeyConstants.CITY_KEY,id),id);
    }

    @Override
    public City queryCityById(String key, Integer cityId) {
        return this.getCityCacheById(key,cityId);
    }

    /**
     * 根据城市 ID 获取缓存
     *
     * @param cityId 城市 ID（不可为 null）
     * @return 城市对象（null 表示无缓存或缓存解析失败）
     */
    public City getCityCacheById(String targetKey,Integer cityId) {
        // 1. 入参校验
        if (cityId == null) {
            log.warn("获取城市缓存失败：城市 ID 为 null");
            return null;
        }

        // 2. 生成目标 Key（与写入逻辑一致）

        log.debug("获取城市缓存，Key：{}", targetKey);

        // 3. 调用 Redis 读取 List 数据（用 RedisCallback 操作字节数组，避免序列化问题）
        List<byte[]> cityByteList = redisTemplate.execute((RedisCallback<List<byte[]>>) redisConnection -> {
            byte[] keyBytes = targetKey.getBytes(StandardCharsets.UTF_8);
            // lRange(key, 0, -1)：获取 List 中所有元素（此处仅 1 个元素）
            return redisConnection.lRange(keyBytes, 0, -1);
        });

        // 4. 解析数据（List → JSON → City 对象）
        if (CollectionUtils.isEmpty(cityByteList)) {
            log.info("城市缓存不存在，targetKey：{}", targetKey);
            return null;
        }

        try {
            // 取 List 中第一个元素（写入时仅存 1 个元素）
            byte[] cityBytes = cityByteList.get(0);
            String cityJson = new String(cityBytes, StandardCharsets.UTF_8);
            return JSON.parseObject(cityJson, City.class); // 反向解析为 City 对象
        } catch (Exception e) {
            log.error("解析城市缓存失败，Key：{}", targetKey, e);
            return null;
        }
    }

    /**
     * 批量获取城市缓存
     *
     * @param cityIds 城市 ID 集合（不可为 null 或空）
     * @return 城市对象列表（顺序与输入 ID 一致，无缓存的位置为 null）
     */
    @Override
    public List<City> batchGetCityCache(List<Integer> cityIds) {
        // 1. 入参校验
        if (CollectionUtils.isEmpty(cityIds)) {
            return Collections.emptyList();
        }

        // 1. 拼接 keys
        List<String> keys = cityIds.stream()
                .map(id -> String.format(RedisKeyConstants.CITY_KEY, id))
                .collect(Collectors.toList());

        // 2. pipeline 获取
        List<Object> rawCityList = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (String key : keys) {
                connection.stringCommands().get(key.getBytes(StandardCharsets.UTF_8));
            }
            return null;
        });

        // 3. 反序列化
        return rawCityList.stream()
                .filter(Objects::nonNull)
                .map(val -> (City) redisTemplate.getValueSerializer().deserialize((byte[]) val))
                .collect(Collectors.toList());
    }

    /**
     * 全量获取所有城市缓存（通过 Key 模板匹配所有符合的 Key）
     *
     * @return 所有城市缓存列表（无缓存时返回空列表）
     */
    @Override
    public List<City> getAllCityCache() {
        // 1. 构造 Key 匹配模式
        String keyPattern = RedisKeyConstants.CITY_KEY.replace("%s", "*"); // city:id:*
        log.debug("全量获取城市缓存，Key 匹配模式：{}", keyPattern);

        // 2. 使用 SCAN 获取所有匹配的 Key
        Set<String> allCityKeys = new HashSet<>();
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            try (Cursor<byte[]> cursor = connection.scan(
                    ScanOptions.scanOptions().match(keyPattern).count(200).build())) {
                while (cursor.hasNext()) {
                    allCityKeys.add(new String(cursor.next(), StandardCharsets.UTF_8));
                }
            }
            return null;
        });

        if (CollectionUtils.isEmpty(allCityKeys)) {
            log.info("无任何城市缓存，Key 匹配模式：{}", keyPattern);
            return Collections.emptyList();
        }

        // 3. pipeline 批量获取 Value
        List<Object> rawCityList = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (String key : allCityKeys) {
                connection.stringCommands().get(key.getBytes(StandardCharsets.UTF_8));
            }
            return null;
        });

        // 4. 反序列化为 City 对象
        List<City> cityList = rawCityList.stream()
                .filter(Objects::nonNull)
                .map(val -> (City) redisTemplate.getValueSerializer().deserialize((byte[]) val))
                .collect(Collectors.toList());

        log.info("获取到城市缓存数量：{}", cityList.size());
        return cityList;
    }
}
